package com.lgmshare.component.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.lgmshare.component.R;

/**
 * @author: lim
 * @description: 分别设置加载中、空数据、加载数据失败三种状态的显示
 * @email: lgmshare@gmail.com
 * @datetime 2014年6月18日  下午3:55:08
 */
public class StatusLayout extends RelativeLayout {

    // ---------------------------
    // static variables
    // ---------------------------

    /**
     * The none state
     */
    public final static int TYPE_NONE = 0;
    /**
     * The empty state
     */
    public final static int TYPE_EMPTY = 1;
    /**
     * The loading state
     */
    public final static int TYPE_LOADING = 2;
    /**
     * The error state
     */
    public final static int TYPE_ERROR = 3;

    private Context mContext;

    private ViewGroup mLoadingView;
    private ViewGroup mEmptyView;
    private ViewGroup mErrorView;

    private LayoutInflater mInflater;

    private OnClickListener mLoadingButtonClickListener;
    private OnClickListener mEmptyButtonClickListener;
    private OnClickListener mErrorButtonClickListener;

    // ---------------------------
    // default values
    // ---------------------------
    private int mPageType = TYPE_NONE;
    private String mLoadingMessage;
    private String mErrorMessage;
    private String mEmptyMessage;

    private int mLoadingMessageViewId;
    private int mErrorMessageViewId;
    private int mEmptyMessageViewId;
    private int mLoadingViewButtonId;
    private int mErrorViewButtonId;
    private int mEmptyViewButtonId;

    private boolean mShowLoadingButton = true;
    private boolean mShowEmptyButton = true;
    private boolean mShowErrorButton = true;

    private String mLoadingButtonName;
    private String mEmptyButtonName;
    private String mErrorButtonName;

    private LayoutParams mLayoutParams;

    /**
     * Constructor
     *
     * @param context the context (preferred context is any activity)
     */
    public StatusLayout(Context context) {
        super(context);
        init(context);
    }

    public StatusLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public StatusLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    // ---------------------------
    // getters and setters
    // ---------------------------

    /**
     * Gets the loading layout
     *
     * @return the loading layout
     */
    public ViewGroup getLoadingView() {
        return mLoadingView;
    }

    /**
     * Sets loading layout
     *
     * @param loadingView the layout to be shown when the list is loading
     */
    public void setLoadingView(ViewGroup loadingView) {
        this.mLoadingView = loadingView;
        addView(mLoadingView, mLayoutParams);
    }

    /**
     * Sets loading layout resource
     *
     * @param res the resource of the layout to be shown when the list is loading
     */
    public void setLoadingViewRes(int res) {
        this.mLoadingView = (ViewGroup) mInflater.inflate(res, null);
        addView(mLoadingView, mLayoutParams);
    }

    /**
     * Sets the message to be shown when the list is being loaded
     *
     * @param loadingMessage the message
     */
    public void setLoadingMessage(String loadingMessage) {
        this.mLoadingMessage = loadingMessage;
    }

    /**
     * Sets the message to be shown when the list is being loaded
     *
     * @param messageViewId the id of the text view within the loading layout whose text will be changed into this message
     */
    public void setLoadingMessageViewId(int messageViewId) {
        this.mLoadingMessageViewId = messageViewId;
    }

    /**
     * Sets the OnClickListener to LoadingView
     *
     * @param loadingButtonClickListener OnClickListener Object
     */
    public void setLoadingButtonClickListener(OnClickListener loadingButtonClickListener) {
        this.mLoadingButtonClickListener = loadingButtonClickListener;
    }

    /**
     * Sets the OnClickListener to LoadingView
     *
     * @param loadingButtonClickListener OnClickListener Object
     */
    public void setLoadingButtonClickListener(String name, OnClickListener loadingButtonClickListener) {
        this.mLoadingButtonName = name;
        this.mLoadingButtonClickListener = loadingButtonClickListener;
    }

    /**
     * Gets the empty layout
     *
     * @return the empty layout
     */
    public ViewGroup getEmptyView() {
        return mEmptyView;
    }

    /**
     * Sets empty layout
     *
     * @param emptyView the layout to be shown when no items are available to load in the list
     */
    public void setEmptyView(ViewGroup emptyView) {
        this.mEmptyView = emptyView;
        addView(mEmptyView, mLayoutParams);
    }

    /**
     * Sets empty layout resource
     *
     * @param res the resource of the layout to be shown when no items are available to load in the list
     */
    public void setEmptyViewRes(int res) {
        this.mEmptyView = (ViewGroup) mInflater.inflate(res, null);
        addView(mEmptyView, mLayoutParams);
    }

    /**
     * Sets the message to be shown when the list will be empty for not having any item to display
     *
     * @param emptyMessage the message
     */
    public void setEmptyMessage(String emptyMessage) {
        this.mEmptyMessage = emptyMessage;
    }

    /**
     * Sets the message to be shown when the list will be empty for not having any item to display
     *
     * @param messageViewId the id of the text view within the empty layout whose text will be changed into this message
     */
    public void setEmptyMessageViewId(int messageViewId) {
        this.mEmptyMessageViewId = messageViewId;
    }

    /**
     * Sets the OnClickListener to EmptyView
     *
     * @param emptyButtonClickListener OnClickListener Object
     */
    public void setEmptyButtonClickListener(OnClickListener emptyButtonClickListener) {
        this.mEmptyButtonClickListener = emptyButtonClickListener;
    }

    /**
     * Sets the OnClickListener to EmptyView
     *
     * @param emptyButtonClickListener OnClickListener Object
     */
    public void setEmptyButtonClickListener(String name, OnClickListener emptyButtonClickListener) {
        this.mEmptyButtonName = name;
        this.mEmptyButtonClickListener = emptyButtonClickListener;
    }

    /**
     * Gets the error layout
     *
     * @return the error layout
     */
    public ViewGroup getErrorView() {
        return mErrorView;
    }

    /**
     * Sets error layout
     *
     * @param errorView the layout to be shown when list could not be loaded due to some error
     */
    public void setErrorView(ViewGroup errorView) {
        this.mErrorView = errorView;
        addView(mErrorView, mLayoutParams);
    }

    /**
     * Sets error layout resource
     *
     * @param res the resource of the layout to be shown when list could not be loaded due to some error
     */
    public void setErrorViewRes(int res) {
        this.mErrorView = (ViewGroup) mInflater.inflate(res, null);
        addView(mErrorView, mLayoutParams);
    }

    /**
     * Sets the message to be shown when the list could not be loaded due to some error
     *
     * @param errorMessage the error message
     */
    public void setErrorMessage(String errorMessage) {
        this.mErrorMessage = errorMessage;
    }

    /**
     * Sets the message to be shown when the list is being loaded
     *
     * @param messageViewId the id of the text view within the loading layout whose text will be changed into this message
     */
    public void setErrorMessageViewId(int messageViewId) {
        this.mErrorMessageViewId = messageViewId;
    }

    /**
     * Sets the OnClickListener to ErrorView
     *
     * @param errorButtonClickListener OnClickListener Object
     */
    public void setErrorButtonClickListener(OnClickListener errorButtonClickListener) {
        this.mErrorButtonClickListener = errorButtonClickListener;
    }

    /**
     * Sets defaultView button name and clickListener
     * Sets the OnClickListener to ErrorView
     *
     * @param errorButtonClickListener OnClickListener Object
     */
    public void setErrorButtonClickListener(String name, OnClickListener errorButtonClickListener) {
        this.mErrorButtonName = name;
        this.mErrorButtonClickListener = errorButtonClickListener;
    }

    /**
     * Sets if a button will be shown in the empty view
     *
     * @param showEmptyButton will a button be shown in the empty view
     */
    public void setEmptyButtonStatus(boolean showEmptyButton) {
        this.mShowEmptyButton = showEmptyButton;
    }

    /**
     * Sets if a button will be shown in the loading view
     *
     * @param showLoadingButton will a button be shown in the loading view
     */
    public void setLoadingButtonStatus(boolean showLoadingButton) {
        this.mShowLoadingButton = showLoadingButton;
    }

    /**
     * Sets if a button will be shown in the error view
     *
     * @param showErrorButton will a button be shown in the error view
     */
    public void setErrorButtonStatus(boolean showErrorButton) {
        this.mShowErrorButton = showErrorButton;
    }

    // ---------------------------
    // private methods
    // ---------------------------

    private void changePageType() {
        setDefaultValues();
        refreshMessages();

        switch (mPageType) {
            case TYPE_EMPTY:
                if (mEmptyView != null) {
                    mEmptyView.startAnimation(getShowAnimation());
                    mEmptyView.setVisibility(View.VISIBLE);
                }
                if (mErrorView != null) {
                    mErrorView.setVisibility(View.GONE);
                }
                if (mLoadingView != null) {
                    mLoadingView.setVisibility(View.GONE);
                }
                setVisibility(View.VISIBLE);
                break;
            case TYPE_ERROR:
                if (mEmptyView != null) {
                    mEmptyView.setVisibility(View.GONE);
                }
                if (mErrorView != null) {
                    mErrorView.startAnimation(getShowAnimation());
                    mErrorView.setVisibility(View.VISIBLE);
                }
                if (mLoadingView != null) {
                    mLoadingView.setVisibility(View.GONE);
                }
                setVisibility(View.VISIBLE);
                break;
            case TYPE_LOADING:
                if (mEmptyView != null) {
                    mEmptyView.setVisibility(View.GONE);
                }
                if (mErrorView != null) {
                    mErrorView.setVisibility(View.GONE);
                }
                if (mLoadingView != null) {
                    mLoadingView.setVisibility(View.VISIBLE);
                }
                setVisibility(View.VISIBLE);
                break;
            case TYPE_NONE:
                if (mEmptyView != null) {
                    mEmptyView.setVisibility(View.GONE);
                }
                if (mErrorView != null) {
                    mErrorView.setVisibility(View.GONE);
                }
                if (mLoadingView != null) {
                    mLoadingView.setVisibility(View.GONE);
                }
                setVisibility(View.GONE);
                break;
            default:
                break;
        }
    }

    private void refreshMessages() {
        Resources res = mContext.getResources();
        switch (mPageType) {
            case TYPE_LOADING:
                if (mLoadingMessageViewId > 0) {
                    TextView view = mLoadingView.findViewById(mLoadingMessageViewId);
                    if (mLoadingMessage != null) {
                        view.setText(mLoadingMessage);
                    } else {
                        view.setText(res.getString(R.string.status_layout_message_loading));
                    }
                }
                break;
            case TYPE_EMPTY:
                if (mEmptyMessageViewId > 0) {
                    TextView view = mEmptyView.findViewById(mEmptyMessageViewId);
                    if (mEmptyMessage != null) {
                        view.setText(mEmptyMessage);
                    } else {
                        view.setText(res.getString(R.string.status_layout_message_empty));
                    }
                }
                break;
            case TYPE_ERROR:
                if (mErrorMessageViewId > 0) {
                    TextView view = mErrorView.findViewById(mErrorMessageViewId);
                    if (mErrorMessage != null) {
                        view.setText(mErrorMessage);
                    } else {
                        view.setText(res.getString(R.string.status_layout_message_error));
                    }
                }
                break;
            default:
                break;
        }
    }

    @SuppressLint("InflateParams")
    private void setDefaultValues() {
        switch (mPageType) {
            case TYPE_LOADING:
                if (mLoadingView == null) {
                    mLoadingView = (ViewGroup) mInflater.inflate(R.layout.status_layout_loading, null);
                    mLoadingMessageViewId = R.id.status_loading_message;
                    mLoadingViewButtonId = R.id.status_loading_button;

                    if (mShowLoadingButton && mLoadingButtonClickListener != null) {
                        Button loadingViewButton = mLoadingView.findViewById(mLoadingViewButtonId);
                        if (loadingViewButton != null) {
                            loadingViewButton.setOnClickListener(mLoadingButtonClickListener);
                            loadingViewButton.setVisibility(View.VISIBLE);
                        }
                        if (!TextUtils.isEmpty(mLoadingButtonName)) {
                            loadingViewButton.setText(mLoadingButtonName);
                        }
                    } else {
                        View loadingViewButton = mLoadingView.findViewById(mLoadingViewButtonId);
                        loadingViewButton.setVisibility(View.GONE);
                    }
                    addView(mLoadingView, mLayoutParams);
                }
                break;
            case TYPE_EMPTY:
                if (mEmptyView == null) {
                    mEmptyView = (ViewGroup) mInflater.inflate(R.layout.status_layout_empty, null);
                    mEmptyMessageViewId = R.id.status_empty_message;
                    mEmptyViewButtonId = R.id.status_empty_button;

                    if (mShowEmptyButton && mEmptyButtonClickListener != null) {
                        Button emptyViewButton = mEmptyView.findViewById(mEmptyViewButtonId);
                        if (emptyViewButton != null) {
                            emptyViewButton.setOnClickListener(mEmptyButtonClickListener);
                            emptyViewButton.setVisibility(View.VISIBLE);
                        }
                        if (!TextUtils.isEmpty(mEmptyButtonName)) {
                            emptyViewButton.setText(mEmptyButtonName);
                        }
                    } else {
                        View emptyViewButton = mEmptyView.findViewById(mEmptyViewButtonId);
                        emptyViewButton.setVisibility(View.GONE);
                    }
                    addView(mEmptyView, mLayoutParams);
                }
                break;
            case TYPE_ERROR:
                if (mErrorView == null) {
                    mErrorView = (ViewGroup) mInflater.inflate(R.layout.status_layout_error, null);
                    mErrorMessageViewId = R.id.status_error_message;
                    mErrorViewButtonId = R.id.status_error_button;

                    if (mShowErrorButton && mErrorButtonClickListener != null) {
                        Button errorViewButton = mErrorView.findViewById(mErrorViewButtonId);
                        if (errorViewButton != null) {
                            errorViewButton.setOnClickListener(mErrorButtonClickListener);
                            errorViewButton.setVisibility(View.VISIBLE);
                        }
                        if (!TextUtils.isEmpty(mErrorButtonName)) {
                            errorViewButton.setText(mErrorButtonName);
                        }
                    } else {
                        View errorViewButton = mErrorView.findViewById(mErrorViewButtonId);
                        errorViewButton.setVisibility(View.GONE);
                    }
                    addView(mErrorView, mLayoutParams);
                }
                break;
            default:
                break;
        }
    }

    // ---------------------------
    // public methods
    // ---------------------------

    /**
     * Shows the empty layout if the list is empty
     */
    public void showEmpty() {
        this.mPageType = TYPE_EMPTY;
        changePageType();
    }

    /**
     * Shows the loading layout if the list is loading
     */
    public void showLoading() {
        this.mPageType = TYPE_LOADING;
        changePageType();
    }

    /**
     * Shows the error layout if the list is error
     */
    public void showError() {
        this.mPageType = TYPE_ERROR;
        changePageType();
    }

    /**
     * Shows the noting else layout if the load success
     */
    public void hide() {
        this.mPageType = TYPE_NONE;
        changePageType();
    }

    private Animation getShowAnimation() {
        /*AlphaAnimation animation = new AlphaAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
                Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
                -1.0f, Animation.RELATIVE_TO_SELF, 0.0f);*/
        AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);
        animation.setDuration(500);
        return animation;
    }

    private Animation getHideAnimation() {
       /*AlphaAnimation animation = new AlphaAnimation(Animation.RELATIVE_TO_SELF,
                0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
                Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
                -1.0f);*/
        AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
        animation.setDuration(500);
        return animation;
    }
}
